#include "PerfTimer.h"
#include "StringUtil.h"

using namespace WONAPI;

static __int64 gPerfTotalTime = 0;
static __int64 gPerfStartTick = 0;
static __int64 gPerfResetTick = 0;
static double gPerfElapsedTime = 0;
static int gPerfTimerStartCount = 0;
static bool gPerfTimerStarted = false;
typedef std::map<std::string,__int64,StringLessNoCase> PerfTimeMap;

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
PerfTimer::PerfTimer(const char *theName)
{
	mName = theName;
	mStarted = false;
	Start();
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
PerfTimer::~PerfTimer()
{
	Stop();
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static __int64 MyQueryPerformanceCounter()
{
//	LARGE_INTEGER anInt;
//	QueryPerformanceCounter(&anInt);
//	return anInt.QuadPart;

	unsigned long x,y;
	_asm
	{
		rdtsc
		mov x, eax
		mov y, edx
	}

	__int64 result = y;
	result<<=32;
	result|=x;
	return result;
}


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static __int64 MyQueryPerformanceFrequency()
{
	static __int64 aFreq = 0;
	if(aFreq!=0)
		return aFreq;

	LARGE_INTEGER s1, e1, f1;
	__int64 s2, e2, f2;
	QueryPerformanceCounter(&s1);
	s2 = MyQueryPerformanceCounter();
	Sleep(50);
	e2 = MyQueryPerformanceCounter();
	QueryPerformanceCounter(&e1);
	QueryPerformanceFrequency(&f1);

	double aTime = (double)(e1.QuadPart - s1.QuadPart)/f1.QuadPart;
	f2 = (e2 - s2)/aTime;
	aFreq = f2;

	return aFreq;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void PerfTimer::Start()
{
	if(mName!=NULL)
		return;

	if(!mStarted)
	{
		mStarted = true;

		gPerfTimerStartCount++;
		if(gPerfTimerStartCount==1)
			gPerfStartTick = MyQueryPerformanceCounter();
	}
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void PerfTimer::Stop()
{
	if(mName!=NULL)
		return;

	if(mStarted)
	{
		gPerfTimerStartCount--;
		if(gPerfTimerStartCount<=0 && gPerfTimerStarted)
		{
			gPerfTotalTime += MyQueryPerformanceCounter() - gPerfStartTick;
			gPerfTimerStartCount = 0;
		}
		else
		{
			int x = 0;
			x++;
		}
		mStarted = false;
	}
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
double PerfTimer::GetCountedTime(const char *theName)
{
	__int64 aFreq = MyQueryPerformanceFrequency();
	if(aFreq==0)
		return gPerfTotalTime;
	else
		return (double)gPerfTotalTime/aFreq*1000.0;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
double PerfTimer::GetElapsedTime(const char *theName)
{
	return gPerfElapsedTime;
}
	
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
double PerfTimer::GetPercentTime(const char *theName)
{
	if(gPerfElapsedTime==0)
		return 0;
	else
		return GetCountedTime()/gPerfElapsedTime;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void PerfTimer::GlobalStart(const char *theName)
{
	gPerfTimerStarted = true;
	gPerfTotalTime = 0;
	gPerfTimerStartCount = 0;
	gPerfElapsedTime = 0;

	LARGE_INTEGER anInt; QueryPerformanceCounter(&anInt);
	gPerfResetTick = anInt.QuadPart;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void PerfTimer::GlobalStop(const char *theName)
{
	LARGE_INTEGER anInt; QueryPerformanceCounter(&anInt);
	LARGE_INTEGER aFreq; QueryPerformanceFrequency(&aFreq);
	gPerfElapsedTime = (double)(anInt.QuadPart - gPerfResetTick)/aFreq.QuadPart*1000.0;
	gPerfTimerStarted = false;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void PerfTimer::DumpTimesToStr(std::string &theStr)
{
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void PerfTimer::DumpTimesToFile(const char *theFileName)
{
}

